﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Diagnostics;
using System.Security;
using System.Security.Permissions;
using System.Drawing.Imaging;

namespace ClipboardManager
{
    public partial class FormMain : Form
    {
        int ScreenWidth = 0;
        List<ClipboardItem> ClipboardList = new List<ClipboardItem>();

        private bool IsMouseDown = false;
        private int mouseLastPos = 0;

        private int PixelsToMove = 0;

        private byte MenuImage = 0;
        private bool OpenMenu = false;
        private bool IsMoving = false;

        private const int sMargin = 2;

        private const int sDefaultFontSize = 12;
        private const int sMaxFontSize = 14;
        private const int sMinFontSize = 8;

        private const int sMaxLines = 3;
        private const int sMaxPictureHeight = 50;

        TimeLog timeLog;

        private const int MenuFirst = 5;
        private const int MenuSecond = 20;
        private const int MenuThird = 50;
        private const int MenuFourth = 75;

        public FormMain()
        {
            InitializeComponent();

            nextClipboardViewer = NativeMethods.SetClipboardViewer(this.Handle);

            foreach (Screen i in Screen.AllScreens) { ScreenWidth += i.Bounds.Width; }

            this.Left = ScreenWidth - this.Size.Width;
            this.Top = (Screen.PrimaryScreen.Bounds.Height / 2) - this.Height;

#if DEBUG
            label1.Visible = true;
            label1.Text = Application.ProductVersion;
#endif
        }


        #region ClipboardManager Hook


        IntPtr nextClipboardViewer;

        const int WM_DRAWCLIPBOARD = 0x308;
        const int WM_CHANGECBCHAIN = 0x030D;

        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted=true)]
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_DRAWCLIPBOARD:
                    UpdateClipboard();
                    NativeMethods.SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;

                case WM_CHANGECBCHAIN:
                    if (m.WParam == nextClipboardViewer)
                        nextClipboardViewer = m.LParam;
                    else
                        NativeMethods.SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);
                    break;

                default:
                    base.WndProc(ref m);

                    break;
            }
        }


        #endregion


        private void UpdateClipboard()
        {
            timeLog = new TimeLog("Clipboard Uppdated! Adding new item");

            ClipboardItem ClipItem = new ClipboardItem();
            
            timeLog.NewLog("Adding to list");

            this.ClipboardList.Add(ClipItem);
            AddBox(ClipItem);

            timeLog.EndLog();
            
        }


        private void AddBox(ClipboardItem ClipItem)
        {
            string RtfText = "";

            switch (ClipItem.ClipboardType)
            {
                case ClipboardItem.Type.Text:
                    RtfText = Helper.Trim(ClipItem.DataString);
                    AddTextBox(RtfText, false);
                    break;

                case ClipboardItem.Type.Html:
                    RtfText = Helper.Trim(ClipItem.DataString);
                    AddTextBox(RtfText, false);
                    break;

                case ClipboardItem.Type.Rtf:
                    RtfText = Helper.TrimRtf(ClipItem.DataString);
                    AddTextBox(RtfText, true);
                    break;

                case ClipboardItem.Type.Bitmap:
                    AddPictureBox(ClipItem.DataBitmap);
                    break;

                case ClipboardItem.Type.Files:
                    RtfText = Helper.Trim(ClipItem.DataString);
                    AddTextBox(RtfText, false);
                    break;

                default:
                    break;
            }

            ClipItem.Rtf = RtfText;
        }

        private void AddTextBox(string text, bool IsRtf)
        {
            RichTextBox NewBox = new RichTextBox();

            if (IsRtf)
                NewBox.Rtf = text;
            else
                NewBox.Text = text;

            int BoxHeight = 13;
            if (NewBox.Lines.Length > sMaxLines) BoxHeight = (int)NewBox.SelectionFont.Height * sMaxLines;
            else BoxHeight = (int)NewBox.SelectionFont.Height * NewBox.Lines.Length;

            panel1.Height += BoxHeight + 2;
            PixelsToMove += BoxHeight + 2;
            tim.Start();

            NewBox.Size = new Size(this.Width - (sMargin * 2), BoxHeight);
            NewBox.Left = sMargin;
            NewBox.Top = panel1.Height - NewBox.Height;
            NewBox.Multiline = true;
            NewBox.BorderStyle = BorderStyle.None;
            NewBox.WordWrap = false;
            NewBox.ScrollBars = RichTextBoxScrollBars.None;
            NewBox.BackColor = Color.Gray;
            NewBox.Cursor = Cursors.Default;
            NewBox.ReadOnly = true;
            NewBox.SelectionBackColor = NewBox.BackColor;
            NewBox.Name = NewBox.Text.Length.ToString().PadRight(8,' ') + ClipboardList.Count.ToString();

            NewBox.MouseDown += new MouseEventHandler(StartMove);
            NewBox.MouseMove += new MouseEventHandler(MoveList);
            NewBox.MouseUp += new MouseEventHandler(StopMove);
            NewBox.SelectionChanged += new EventHandler(PreventSelection);

            this.panel1.Controls.Add(NewBox);
        }

        private void AddPictureBox(Bitmap image)
        {
            PictureBox picBox = new PictureBox();

            int BoxHeight = image.Height;
            if (BoxHeight > sMaxPictureHeight) BoxHeight = sMaxPictureHeight;

            panel1.Height += BoxHeight;
            PixelsToMove += BoxHeight;
            tim.Start();

            picBox.Image = image;
            picBox.Size = new Size(this.panel1.Width - (sMargin * 2), BoxHeight);
            picBox.Top = panel1.Height - BoxHeight;
            picBox.SizeMode = PictureBoxSizeMode.Zoom;
            picBox.BackColor = Color.Transparent;
            picBox.Name = "TextBox " + ClipboardList.Count.ToString();
            
            picBox.Left = sMargin;

            picBox.MouseDown += new MouseEventHandler(StartMove);
            picBox.MouseMove += new MouseEventHandler(MoveList);
            picBox.MouseUp += new MouseEventHandler(StopMove);

            this.panel1.Controls.Add(picBox);
        }


        private void ShowWindow(object sender, KeyEventArgs e)
        {
            this.Show();
        }

        private void HideWindow(object sender, KeyEventArgs e)
        {
            this.Hide();
        }


        private void StartMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                IsMouseDown = true;
                mouseLastPos = Cursor.Position.Y;
            }

            else if (e.Button == MouseButtons.Right)
                ShowDetailedClipboardItem(sender);
        }

        private void MoveList(object sender, MouseEventArgs e)
        {
            if (IsMouseDown)
            {
                PixelsToMove += mouseLastPos - Cursor.Position.Y;
                tim.Start();
                mouseLastPos = Cursor.Position.Y;
                this.Invalidate();
                
            }
        }

        private void StopMove(object sender, MouseEventArgs e)
        {
            IsMouseDown = false;
        }


        private void FormMain_MouseLeave(object sender, EventArgs e)
        {
            StopMove(sender, new MouseEventArgs(MouseButtons.None, 0, 0, 0, 0));
        }


        private void MoveListTimer_Tick(object sender, EventArgs e)
        {
            if (PixelsToMove == 0)
            {
                tim.Stop();
                return;
            }

            if (PixelsToMove > 0)
                MoveListUp();

            else
                MoveListDown();

        }

        private void MoveListUp()
        {

            switch (PixelsToMove)
            {
                case 1:
                    this.panel1.Top--;
                    this.PixelsToMove = 0;
                    tim.Stop();
                    break;

                case 2:
                    this.panel1.Top--;
                    this.PixelsToMove--;
                    break;

                case 3:
                    this.panel1.Top -= 2;
                    this.PixelsToMove -= 2;
                    break;

                case 4:
                    this.panel1.Top -= 2;
                    this.PixelsToMove -= 2;
                    break;

                case 5:
                    this.panel1.Top -= 2;
                    this.PixelsToMove -= 2;
                    break;

                default:
                    int MoveApply = (int)PixelsToMove / 4;
                    PixelsToMove -= MoveApply;
                    this.panel1.Top -= MoveApply;
                    break;
            }

            if (panel1.Bottom < 0)
            {
                IsMouseDown = false;
                PixelsToMove = panel1.Bottom - 400;
            }
        }

        private void MoveListDown()
        {
            switch (PixelsToMove)
            {
                case -1:
                    this.panel1.Top++;
                    this.PixelsToMove = 0;
                    tim.Stop();
                    break;

                case -2:
                    this.panel1.Top++;
                    this.PixelsToMove++;
                    break;

                case -3:
                    this.panel1.Top += 2;
                    this.PixelsToMove += 2;
                    break;

                case -4:
                    this.panel1.Top += 2;
                    this.PixelsToMove += 2;
                    break;

                case -5:
                    this.panel1.Top += 2;
                    this.PixelsToMove += 2;
                    break;

                default:
                    int MoveApply = (int)PixelsToMove / 4;
                    MoveApply = (MoveApply - MoveApply) - MoveApply;
                    PixelsToMove += MoveApply;
                    this.panel1.Top += MoveApply;
                    break;
            }

            if (panel1.Top > 400)
            {
                IsMouseDown = false;
                PixelsToMove = 400 + (panel1.Top -400);
            }
        }


        private void PreventSelection(object sender, EventArgs e)
        {
            ((RichTextBox)sender).Select(0, 0);
        }

        private void ShowDetailedClipboardItem(object sender)
        {
            string SenderName = sender.GetType().Name;
            bool IsBitmap = false;

            if (!SenderName.StartsWith("RichTextBox") && !SenderName.StartsWith("PictureBox"))
                return;

            if (SenderName == "RichTextBox")
                SenderName = ((RichTextBox)sender).Name;

            else if (SenderName == "PictureBox")
            {
                SenderName = ((PictureBox)sender).Name;
                IsBitmap = true;
            }
            else
                return;
            
            string ClipIndexString = (SenderName.Substring(8, SenderName.Length - 8));
            int ClipIndex = int.Parse(ClipIndexString) - 1;

            ClipboardItem cbi = ClipboardList[ClipIndex];

            if (!IsBitmap)
                cbi.info.Length = SenderName.Substring(0, 8);

            FormClipboardItem FormItem = new FormClipboardItem(cbi);
            FormItem.Left = ScreenWidth - FormItem.Width - this.Width - 20;
            FormItem.Top = this.Top + 20;
            FormItem.Show();


            MainClass.Log("New Detailed Clipboard Form: " + cbi.ToString());
        }


        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            NativeMethods.ChangeClipboardChain(this.Handle, nextClipboardViewer);
            Application.Exit();
        }


        private void MenuTimer_Tick(object sender, EventArgs e)
        {
            if (OpenMenu)
            {
                if (MainMenu.Location.Y == 0)
                {
                    MenuTimer.Stop();
                    return;
                }

                MoveMenu(2);
            }

            if (!OpenMenu)
            {
                if (MainMenu.Location.Y == -MainMenu.Height)
                {
                    MenuTimer.Stop();
                    return;
                }

                MoveMenu(-2);
            }
        }


        private void MoveMenu(int value)
        {
            MainMenu.Top += value;
            TabMenu.Top += value;
        }

        private void TabMenu_MouseEnter(object sender, EventArgs e)
        {
            OpenMenu = true;
            MenuTimer.Start();
        }

        private void TabMenu_MouseLeave(object sender, EventArgs e)
        {
            OpenMenu = false;
            MenuTimer.Start();
        }

        private void MainMenu_MouseEnter(object sender, EventArgs e)
        {
            OpenMenu = true;
        }

        private void MainMenu_MouseLeave(object sender, EventArgs e)
        {
            if (IsMoving)
                return;

            OpenMenu = false;
            MenuTimer.Start();
            
            if (MenuImage != 0)
            {
                MainMenu.Image = MainClass.Menu0;
                MenuImage = 0;
            }
            return;
        }

        private void MainMenu_MouseMove(object sender, MouseEventArgs e)
        {
            int X = e.Location.X;

            if (X < MenuFirst)
            {
                if (MenuImage != 0)
                {
                    MainMenu.Image = MainClass.Menu0;
                    MenuImage = 0;
                }
                return;
            }

            if (X > MenuFirst && X < MenuSecond)
            {
                if (MenuImage != 1)
                {
                    MainMenu.Image = MainClass.Menu1;
                    MenuImage = 1;
                }
                return;
            }

            if (X > MenuSecond && X < MenuThird)
            {
                if (MenuImage != 2)
                {
                    MainMenu.Image = MainClass.Menu2;
                    MenuImage = 2;
                }
                return;
            }

            if (X > MenuThird && X < MenuFourth)
            {
                if (MenuImage != 3)
                {
                    MainMenu.Image = MainClass.Menu3;
                    MenuImage = 3;
                }
                return;
            }

            if (X > MenuFourth)
            {
                if (MenuImage != 0)
                {
                    MainMenu.Image = MainClass.Menu0;
                    MenuImage = 0;
                }
            }
        }

        private void MainMenu_MouseUp(object sender, MouseEventArgs e)
        {
            switch (MenuImage)
            {
                case 1://Minimize
                    this.WindowState = FormWindowState.Minimized;
                    break;


                case 3://Exit
                    DialogResult dialog = MessageBox.Show(Properties.Resources.ExitPromp, "Exit", MessageBoxButtons.OKCancel);

                    if (dialog == System.Windows.Forms.DialogResult.OK)
                    {
                        NativeMethods.ChangeClipboardChain(this.Handle, nextClipboardViewer);
                        Application.Exit();
                    }
                    break;
            }
        }

        private void MainMenu_MouseDown(object sender, MouseEventArgs e)
        {
            if (MenuImage == 2)
            {
                IsMoving = true;
                NativeMethods.ReleaseCapture();
                NativeMethods.SendMessage(Handle, 0xA1, 0x2, 0); //WM_NCLBUTTONDOWN and HT_CAPTION
            }
        }

    }
}


